﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

using Styx.WoWInternals.DBC;
using Styx.WoWInternals.WoWObjects;
using Styx.WoWInternals;
using Styx.Common;
using Styx.CommonBot.Routines;
using Styx.Helpers;
using Styx.Pathing;
using Styx;
using System.Diagnostics;
using System.Threading;
using System.IO;
using Styx.CommonBot;
using System.Windows.Forms;
using Styx.CommonBot.Inventory;

namespace KingWoW
{
    public class RestorationShamanCombatClass : KingWoWAbstractBaseClass
    {

        private static string Name = "KingWoW RestorationShaman";

         #region CONSTANT AND VARIABLES

        //START OF CONSTANTS ==============================
        private const bool LOGGING = true;
        private const bool DEBUG = false;
        private const bool TRACE = false;
        private static KingWoWUtility utils = null;
        private Movement movement = null;
        private ExtraUtils extra = null;
        private ShamanCommon shammyCommon = null;
        WoWUnit CurrentHealtarget = null;
        WoWUnit healTarget = null;
        private TalentManager talents = null;
        private static bool IsCRPaused = false;
        WoWUnit target = null;
        private float chaiHealJumpRaidius = 13f;

        private Random rnd = new Random();
        private int RANDOM_TIME = 0;

        private WoWUnit tank = null;
        private WoWUnit off_tank = null;
        private WoWUnit lastTank = null;
        private WoWUnit lastOffTank = null;
        private bool SoloBotType = false;
        private string BaseBot = "unknown";

        private const string DEBUG_LABEL = "DEBUG";
        private const string TRACE_LABEL = "TRACE";
        private const string TANK_CHANGE = "TANK CHANGED";
        private const string OFF_TANK_CHANGE = "OFF TANK CHANGED";
        private const string FACING = "FACING";

        //START OF SPELLS AND AURAS ==============================
        //private const string DRINK = "Drink";
        //private const string FOOD = "Food";

        
     
        private const string SEARING_TOTEM = "Searing Totem";
        private const string SEARING_FLAMES = "Searing Flames";
        private const string GROUNDING_TOTEM = "Grounding Totem";
        private const string CAPACITOR_TOTEM = "Capacitor Totem";
        private const string SPIRIT_LINK_TOTEM = "Spirit Link Totem";
        private const string EARTHBIND_TOTEM = "Earthbind Totem";
        private const string TREMOR_TOTEM = "Tremor Totem";

        private const string WATER_SHIELD = "Water Shield";
        private const string LIGHTNING_SHIELD = "Lightning Shield";
        private const string EARTH_SHIELD = "Earth Shield";
        private const string LIGHTNING_BOLT = "Lightning Bolt";
        private const string LAVA_BURST = "Lava Burst";
        private const string MAELSTROM_WEAPON = "Maelstrom Weapon";
        private const string WIND_SHEAR = "Wind Shear";      
        private const string FLAME_SHOCK = "Flame Shock";
        private const string EARTH_SHOCK = "Earth Shock";
        private const string LAVA_LASH = "Lava Lash";
        private const string STORMSTRIKE = "Stormstrike";
        private const string STORMBLAST = "Stormblast";
        private const string UNLEASH_LIFE = "Unleash Life";
        private const string FIRE_NOVA = "Fire Nova";
        private const string MAGMA_TOTEM = "Magma Totem";
        private const string CHAIN_LIGHTNING = "Chain Lightning";
        private const string PURIFY_SPIRIT = "Purify Spirit";
        private const string ANCESTRAL_SWIFTNESS = "Ancestral Swiftness";
                                                

        //HEAL
        private const string ANCESTRAL_SPIRIT = "Ancestral Spirit";       
        private const string CHAIN_HEAL = "Chain Heal";
        private const string CLEANSE_SPIRIT = "Cleanse Spirit";
        private const string HEALING_SURGE = "Healing Surge";
        private const string HEALING_RAIN = "Healing Rain";
        private const string HEALING_WAVE = "Healing Wave";

        private const int TIDAL_WAVES = 53390;
              
        
        private const string HEALING_STREAM_TOTEM = "Healing Stream Totem";
        private const string RIPTIDE = "Riptide";

        private const string GHOST_WOLF = "Ghost Wolf";
        private const string HEX = "hex";
        private const string PURGE = "Purge";

        private const string TOTEMIC_RECALL = "Totemic Recall";

        private const int T17_4P_HarmonyOfTheElements_Proc = 167703;
        
   
        

        //CD
        private const string ASCENDANCE = "Ascendance";
        private const string FERAL_SPIRIT = "Feral Spirit";
        private const string FIRE_ELEMENTAL_TOTEM = "Fire Elemental Totem";
        private const string EARTH_ELEMENTAL_TOTEM = "Earth Elemental Totem";
        private const string SPIRIT_WALK = "Spiritwalker's Grace";
        private const string STORMLASH_TOTEM = "Stormlash Totem";
          
        //END OF SPELLS AND AURAS ==============================

        //TALENTS
        private const string STONE_BULWALRK_TOTEM = "Stone Bulwark Totem";
        private const string ASTRAL_SHIFT = "Astral Shift";
        private const string EARTHGRAB_TOTEM = "Earthgrab Totem";
        private const string WINDWALK_TOTEM = "Windwalk Totem";
        private const string TOTEMIC_PROJECTION = "Totemic Projection";
        private const string CALL_OF_THE_ELEMENTS = "Call of the Elements";
        private const string ASTRAL_SWIFTNESS = "Ancestral Swiftness";
        private const string ELEMENTAL_MASTERY = "Elemental Mastery";
        private const string ANCESTRAL_GUIDANCE = "Ancestral Guidance";
        private const string HEALING_TIDE_TOTEM = "Healing Tide Totem";
        private const string CLOUDBURST_TOTEM = "Cloudburst Totem";
        private const string ELEMENTAL_BLAST = "Elemental Blast";
        private const int ECHO_OF_THE_ELEMENTS_BUFF = 159105;

        //FIRE ELEMENTAL TOTEM
        private const string EMPOWER = "Empower";
        //EARTH ELEMENTAL TOTEM
        private const string REINFORCE = "Reinforce";
        //END TALENTS
        //END OF CONSTANTS ==============================

        #endregion


        #region Hotkeys
        private static bool Blanket_RIPTIDE = false;

        /*private static DateTime nextTime_Blanket_RIPTIDE_Allowed = DateTime.Now;

        public static void SetnextTime_Blanket_RIPTIDE_Allowed()
        {
            nextTime_Blanket_RIPTIDE_Allowed = DateTime.Now + new TimeSpan(0, 0, 0, 0, 3000);
        }*/

        private static void InitializeHotkey()
        {
            HotkeysManager.Initialize(StyxWoW.Memory.Process.MainWindowHandle);
        }

        /*private static DateTime nextTime_Pause_Resume_Allowed=DateTime.Now;

        public static void SetnextTime_Pause_Resume_Allowed()
        {
            //1 seconds avoid duuble cast
            nextTime_Pause_Resume_Allowed = DateTime.Now + new TimeSpan(0, 0, 0, 0, 3000);
        }*/

        private static Hotkey RegisterHotkeyAssignment(string name, Keys key, Action<Hotkey> callback)
        {
            Keys keyCode = key & Keys.KeyCode;
            ModifierKeys mods = ModifierKeys.NoRepeat;

            if ((key & Keys.Shift) != 0)
                mods |= ModifierKeys.Shift;
            if ((key & Keys.Alt) != 0)
                mods |= ModifierKeys.Alt;
            if ((key & Keys.Control) != 0)
                mods |= ModifierKeys.Control;

            return HotkeysManager.Register(name, keyCode, mods, callback);
        }

        private static void RegisterHotkeys()
        {
            RegisterHotkeyAssignment("Routine Pause", (Keys)ExtraUtilsSettings.Instance.PauseKey, hk =>
            {
                try
                {
                    //if (nextTime_Pause_Resume_Allowed < DateTime.Now)
                    //{
                        if (!IsCRPaused)
                        {
                            IsCRPaused = true;
                            if (ExtraUtilsSettings.Instance.ViewChatMessages)
                                Lua.DoString(@"print('\124cFFE61515 Paused!')");
                            Logging.Write("KingWoW Routine Paused!");
                        }
                        else
                        {
                            IsCRPaused = false;
                            if (ExtraUtilsSettings.Instance.ViewChatMessages)
                                Lua.DoString(@"print('\124cFF15E61C Resumed!')");
                            Logging.Write("KingWoW Routine Resumed!");
                        }
                        //SetnextTime_Pause_Resume_Allowed();
                    //}
                }
                catch (Exception e)
                {
                    Logging.Write(e.StackTrace);
                }
            });
            RegisterHotkeyAssignment("Blanket_RIPTIDE_Hotkey", (Keys)ExtraUtilsSettings.Instance.Blanket_RIPTIDE_Hotkey, hk =>
            {
                try
                {
                    //if (nextTime_Blanket_RIPTIDE_Allowed < DateTime.Now)
                    //{
                        if (Blanket_RIPTIDE)
                        {
                            Blanket_RIPTIDE = false;
                            if (ExtraUtilsSettings.Instance.ViewChatMessages)
                                Lua.DoString(@"print('\124cFFE61515 Spam RIPTIDE STOP!')");
                            Logging.Write("Spam RIPTIDE STOP!");
                        }
                        else
                        {
                            Blanket_RIPTIDE = true;
                            if (ExtraUtilsSettings.Instance.ViewChatMessages)
                                Lua.DoString(@"print('\124cFF15E61C Spam RIPTIDE START!')");
                            Logging.Write("Spam RIPTIDE START!");
                        }
                        //SetnextTime_Blanket_RIPTIDE_Allowed();
                    //}
                }
                catch (Exception e)
                {
                    Logging.Write(e.StackTrace);
                }
            });
            RegisterHotkeyAssignment("Change_NPC_Healing_Hotkey", (Keys)ExtraUtilsSettings.Instance.Change_NPC_Healing_Hotkey, hk =>
            {
                try
                {
                    if (RestorationShamanSettings.Instance.HealNPC)
                    {
                        RestorationShamanSettings.Instance.HealNPC = false;
                        if (ExtraUtilsSettings.Instance.ViewChatMessages)
                            Lua.DoString(@"print('\124cFFE61515 HealNPC DISABLED!')");
                        Logging.Write("HealNPC DISABLED!");
                    }
                    else
                    {
                        RestorationShamanSettings.Instance.HealNPC = true;
                        if (ExtraUtilsSettings.Instance.ViewChatMessages)
                            Lua.DoString(@"print('\124cFF15E61C HealNPC ENABLED!')");
                        Logging.Write("HealNPC ENABLED!");
                    }
                }
                catch (Exception e)
                {
                    Logging.Write(e.StackTrace);
                }
            });
            RegisterHotkeyAssignment("TotemicProjection", (Keys)ExtraUtilsSettings.Instance.TotemicProjectionHotkey, hk =>
            {
                try
                {
                    Logging.Write("TotemicProjection HOTKEY PRESSED!");
                    TryPutTotemicProjection = true;
                    HotkeyTimer.AutoReset = false;
                    HotkeyTimer.Interval = 2000;
                    HotkeyTimer.Start();
                }
                catch (Exception e)
                {
                    Logging.Write(e.StackTrace);
                }
            });
            RegisterHotkeyAssignment("HealingRainOnHotkey", (Keys)ExtraUtilsSettings.Instance.HealingRainOnHotkey, hk =>
            {
                try
                {
                    Logging.Write("HealingRain HOTKEY PRESSED!");
                    TryPutHealingRain = true;
                    HotkeyTimer.AutoReset = false;
                    HotkeyTimer.Interval = 2000;
                    HotkeyTimer.Start();
                }
                catch (Exception e)
                {
                    Logging.Write(e.StackTrace);

                }

            });
        }

        private static bool TryPutHealingRain = false;
        private static bool TryPutTotemicProjection = false;
        private static System.Timers.Timer HotkeyTimer = new System.Timers.Timer();

        private bool HotkeyHandle()
        {
            if (TryPutHealingRain && utils.CanCast(HEALING_RAIN))
            {
                utils.LogActivity("Healing Rain On Mouse position");
                utils.Cast(HEALING_RAIN);
                utils.PerformSingleLeftMouseClick();
                return true;
            }
            if (TryPutTotemicProjection && utils.CanCast(TOTEMIC_PROJECTION))
            {
                utils.LogActivity("TotemicProjection On Mouse position");
                utils.Cast(TOTEMIC_PROJECTION);
                utils.PerformSingleLeftMouseClick();
                return true;
            }
            return false;
        }

        private void RemoveHotkeys()
        {
            HotkeysManager.Unregister("HealingRainOnHotkey");
            HotkeysManager.Unregister("Routine Pause");
            HotkeysManager.Unregister("Blanket_RIPTIDE_Hotkey");
            HotkeysManager.Unregister("Change_NPC_Healing_Hotkey");
            HotkeysManager.Unregister("TotemicProjection");
            
            
        }

        private void ReRegisterHotkeys()
        {
            RemoveHotkeys();
            RegisterHotkeys();
        }
        #endregion

        public int CurrentCloudTotemValue()
        {
            string command = "local name, rank, icon, count, dispelType, duration, expires, caster, isStealable, shouldConsolidate, spellID, canApplyAura, isBossDebuff, value1, value2, value3 = UnitAura(\"player\", \"Cloudburst Totem\"); return value2";
            int currCloudTotemValue = Lua.GetReturnVal<int>(command, 0);
            return currCloudTotemValue;
        }

        public RestorationShamanCombatClass()
        {
            utils = new KingWoWUtility();
            movement = new Movement();
            extra = new ExtraUtils();
            shammyCommon = new ShamanCommon();
            tank = null;
            lastTank = null; ;
            SoloBotType = false;
            BaseBot = "unknown";
            talents = new TalentManager();
            nextTimeTryReviveAllowed = DateTime.Now;
            HotkeyTimer.Elapsed += HotkeyTimer_Elapsed;
        }

        void HotkeyTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            TryPutHealingRain = false;
            TryPutTotemicProjection = false;
        }

        private DateTime nextTimeTryReviveAllowed;

        public void SetNextTimeTryRevive()
        {
            //2 seconds avoid duuble cast
            nextTimeTryReviveAllowed = DateTime.Now + new TimeSpan(0, 0, 0, 0, 3000);
        }

        private bool MyDeath()
        {
            if (SoloBotType && Me.IsDead && !Me.IsGhost && nextTimeTryReviveAllowed < DateTime.Now)
            {
                Lua.DoString(string.Format("RunMacroText(\"{0}\")", "/script RepopMe()"));
                SetNextTimeTryRevive();
            }
            return false;
        }

        private bool RiptideSpam()
        {
            if (Blanket_RIPTIDE && utils.CanCast(RIPTIDE))
            {
                WoWUnit candidateRiptide = utils.GetNeedMyAuraTarget(RIPTIDE, 40f, RestorationShamanSettings.Instance.HealNPC);
                if (candidateRiptide != null)
                {
                    utils.LogActivity("SPAM RIPTIDE on " + candidateRiptide.SafeName);
                    return utils.Cast(RIPTIDE, candidateRiptide);
                }
                
            }
            return false;
        }

        private bool HealingRain()
        {
            WoWUnit hr_target = null;
            if (!RestorationShamanSettings.Instance.HealingRainOnlyOnMouseLocation && (!Me.IsMoving || utils.isAuraActive(SPIRIT_WALK)) && utils.CanCast(HEALING_RAIN))
            {
                if (RestorationShamanSettings.Instance.HealingRainOnlyOnTankLocation && tank != null &&
                    (utils.AOEHealCount((WoWPlayer)tank, RestorationShamanSettings.Instance.HealingRainPercent, utils.HEALING_RAIN_Radius(), RestorationShamanSettings.Instance.HealNPC) >= RestorationShamanSettings.Instance.HealingRainNumber))
                {
                    hr_target = (WoWPlayer)tank;
                }
                else if (!RestorationShamanSettings.Instance.HealingRainOnlyOnTankLocation)
                {
                    hr_target = utils.BestHealingRainTargetLocation(RestorationShamanSettings.Instance.HealingRainPercent, RestorationShamanSettings.Instance.HealingRainNumber, RestorationShamanSettings.Instance.HealNPC);
                }
                if (hr_target != null)
                {
                    utils.LogActivity(HEALING_RAIN, hr_target.SafeName);
                    utils.Cast(HEALING_RAIN);
                    return SpellManager.ClickRemoteLocation(hr_target.Location);
                }
            }
            return false;
        }

        private bool ChainHealT17()
        {
            WoWUnit ch_target = null;
            if ((!Me.IsMoving || utils.isAuraActive(SPIRIT_WALK)) && utils.CanCast(CHAIN_HEAL) && Me.HasAura(T17_4P_HarmonyOfTheElements_Proc))
            {
                ch_target = utils.BestChaiHeal_Target(RestorationShamanSettings.Instance.ChainHealPercentT17, RestorationShamanSettings.Instance.ChainHealNumberT17, RestorationShamanSettings.Instance.HealNPC, chaiHealJumpRaidius);
                
                if (ch_target != null)
                {
                    if (!utils.isAuraActive(UNLEASH_LIFE) && utils.CanCast(UNLEASH_LIFE))
                    {
                        utils.LogActivity(UNLEASH_LIFE, ch_target.SafeName);
                        utils.Cast(UNLEASH_LIFE, ch_target);
                    }
                    if ((utils.isAuraActive(UNLEASH_LIFE) || !utils.CanCast(UNLEASH_LIFE)) && (utils.isMyAuraActive(RIPTIDE, ch_target) || !utils.CanCast(RIPTIDE)))
                    {
                        utils.LogActivity(" T17 Proc Harmony of the Elements -> "+CHAIN_HEAL, ch_target.SafeName); 
                        return utils.Cast(CHAIN_HEAL, ch_target);
                    }
                }
            }
            return false;

        }

        private bool ChainHeal()
        {
            WoWUnit ch_target = null;
            if ((!Me.IsMoving || utils.isAuraActive(SPIRIT_WALK)) && utils.CanCast(CHAIN_HEAL))
            {
                ch_target = utils.BestChaiHeal_Target(RestorationShamanSettings.Instance.ChainHealPercent, RestorationShamanSettings.Instance.ChainHealNumber, RestorationShamanSettings.Instance.HealNPC, chaiHealJumpRaidius);
                if (ch_target != null)
                {
                    if (!utils.isAuraActive(UNLEASH_LIFE) && utils.CanCast(UNLEASH_LIFE))
                    {
                        utils.LogActivity(UNLEASH_LIFE, ch_target.SafeName);
                        utils.Cast(UNLEASH_LIFE, ch_target);
                    }
                    if ((utils.isAuraActive(UNLEASH_LIFE) || !utils.CanCast(UNLEASH_LIFE)) && (utils.isMyAuraActive(RIPTIDE, ch_target) || !utils.CanCast(RIPTIDE)))
                    {
                        utils.LogActivity(CHAIN_HEAL, ch_target.SafeName); 
                        return utils.Cast(CHAIN_HEAL, ch_target);
                    }
                }
            }
            return false;

        }

        public override bool Pull
        {
            get
            {
                WoWUnit target = Me.CurrentTarget;
                if (target != null && !target.IsFriendly && target.Attackable && !target.IsDead)
                {
                    if (!target.InLineOfSpellSight || target.Distance - target.CombatReach -1 > RestorationShamanSettings.Instance.PullDistance)
                    {
                        movement.KingHealMove(target, RestorationShamanSettings.Instance.PullDistance);
                    }
                    if (!Me.IsFacing(target) && !Me.IsMoving && (RestorationShamanSettings.Instance.AutofaceTarget || SoloBotType))
                    {
                        utils.LogActivity(FACING, target.SafeName);
                        Me.SetFacing(target);
                    }
                    if (utils.CanCast(FLAME_SHOCK))
                    {
                        utils.LogActivity(FLAME_SHOCK, target.SafeName);
                        return utils.Cast(FLAME_SHOCK, target);
                    }
                }
                return false;
            }
        }

        public override bool Pulse
        {
            get
            {
                if (Me.IsDead) return MyDeath();               
                if (Me.Combat || IsCRPaused || (Me.Mounted && !RestorationShamanSettings.Instance.AutoDismountOnCombat) || !StyxWoW.IsInGame || !StyxWoW.IsInWorld || Me.Silenced || utils.IsGlobalCooldown(true) || utils.MeIsChanneling || Me.IsCasting
                || utils.IsEatingOrDrinking() )
                    return false;

                //UPDATE TANK
                tank = utils.SimpleGetTank(40f);
                if (tank == null || !tank.IsValid || !tank.IsAlive) tank = Me;

                if (tank != null && (lastTank == null || lastTank.Guid != tank.Guid))
                {
                    lastTank = tank;
                    utils.LogActivity(TANK_CHANGE, tank.SafeName);
                }
                off_tank = utils.SimpleGetOffTank(40f, tank);
                if (off_tank != null && (lastOffTank == null || lastOffTank.Guid != off_tank.Guid))
                {
                    lastOffTank = off_tank;
                    utils.LogActivity(OFF_TANK_CHANGE, off_tank.SafeName);
                }
                if (RestorationShamanSettings.Instance.AutoGhostWulf && !utils.isAuraActive(GHOST_WOLF) && Me.IsMoving && !Me.Mounted && !Me.IsFalling && !Me.IsDead && !Me.IsGhost
                    && Me.MovementInfo.TimeMoved >= RestorationShamanSettings.Instance.MoveTimeForAutoGhostWulf && !IsCRPaused)
                {
                    utils.LogActivity("moving....autoGhostWolf");
                    return utils.Cast(GHOST_WOLF);
                }
                /*if (tank != null && tank.IsAlive && tank.Distance < 40 && tank.InLineOfSpellSight)
                {
                    //earth shield
                    if (tank.Guid != Me.Guid && (!utils.isAuraActive(EARTH_SHIELD, tank) || utils.GetAuraStack(tank, EARTH_SHIELD, false) <= 1) && utils.CanCast(EARTH_SHIELD))
                    {
                        utils.LogActivity(EARTH_SHIELD, tank.SafeName);
                        return utils.Cast(EARTH_SHIELD, tank);
                    }
                }*/
                HotkeyHandle();                
                //full party or me
                if (!Me.Combat && !Me.Mounted && RestorationShamanSettings.Instance.OOCHealing && !utils.IsEatingOrDrinking())
                {
                    if (RestorationShamanSettings.Instance.UseResurrection) 
                        Resurrect();
                    HealingRain();
                    ChainHeal();

                    healTarget = utils.GetHealTarget(40f, RestorationShamanSettings.Instance.HealNPC);

                    if (healTarget != null)
                    {
                        double hp = healTarget.HealthPercent;
                     
                        if (hp <= RestorationShamanSettings.Instance.RiptidePercent && !utils.isMyAuraActive(RIPTIDE,healTarget) && utils.CanCast(RIPTIDE))
                        {
                            utils.LogHealActivity(healTarget, RIPTIDE, healTarget.SafeName);
                            return utils.Cast(RIPTIDE, healTarget);
                        }
                        if ((!Me.IsMoving || utils.isAuraActive(SPIRIT_WALK)) && !Me.IsCasting && !utils.IsGlobalCooldown() && hp <= RestorationShamanSettings.Instance.HealingWavePercent && utils.CanCast(HEALING_WAVE))
                        {
                            utils.LogHealActivity(healTarget, HEALING_WAVE, healTarget.SafeName);
                            CurrentHealtarget = healTarget;
                            return utils.Cast(HEALING_WAVE, healTarget);
                        }

                    }
                }
                if (!Me.Combat && !IsCRPaused && ((tank != null && tank.Combat) || (off_tank != null && off_tank.Combat)))
                    return CombatRotation();
                return false;
            }
        }

        public override bool Initialize
        {
            get
            {
                Logging.Write("Ciao " + Me.SafeName);
                Logging.Write("Welcome to " + Name + " custom class");
                Logging.Write("Tanks All HonorBuddy Forum developers for code inspiration!");
                Logging.Write("Powered by Attilio76");
                BotEvents.OnBotStartRequested += new BotEvents.OnBotStartStopRequestedDelegate(BotEvents_OnBotStart);
                RegisterHotkeys();

                Logging.Write("************ XML CONFIGURATION ************");
                Logging.Write(RestorationShamanSettings.Instance.GetXML().ToString());
                Logging.Write("*******************************************");
                Logging.Write("*******************************************");
                Logging.Write("*******************************************");
                Logging.Write("************ EXTRA CONFIGURATION ************");
                Logging.Write(ExtraUtilsSettings.Instance.GetXML().ToString());
                Logging.Write("*******************************************");
                return true;
            }
        }

        void BotEvents_OnBotStart(EventArgs args)
        {
            talents.Update();
            ReRegisterHotkeys();
            if (talents.HasGlyph("Chaining"))
            {
                Logging.Write("Glyph of Chaining Detected: increase chainHeal jump radius");
                chaiHealJumpRaidius = 26f;
            }
            else
            {
                Logging.Write("Glyph of Chaining NOT Detected: decrease chainHeal jump radius");
                chaiHealJumpRaidius = 13f;
            }

            BotUpdate();
        }

        public override bool UpdateTalentAndGlyph
        {
            get
            {
                ReRegisterHotkeys();
                talents.Update();
                BotUpdate();
                return true;

            }
        }

        public override bool NeedRest
        {
            get
            {
                if (Me.IsDead || Me.Mounted || Me.InVehicle || (Me.HealthPercent >= 100 && Me.ManaPercent >= 100)) return false;
                if (utils.IsEatingOrDrinking())
                    return true;
                if (Me.ManaPercent <= RestorationShamanSettings.Instance.ManaPercent
                    && !Me.Combat && !Me.IsMoving && !utils.IsEatingOrDrinking())
                {
                    WoWItem mydrink = Consumable.GetBestDrink(false);
                    if (mydrink != null)
                    {
                        utils.LogActivity("Drinking");
                        Styx.CommonBot.Rest.DrinkImmediate();
                        return true;
                    }
                    return true;
                }
                if (Me.HealthPercent <= RestorationShamanSettings.Instance.HealthPercent
                    && !Me.Combat && !Me.IsMoving && !utils.IsEatingOrDrinking())
                {
                    WoWItem myfood = Consumable.GetBestFood(false);
                    if (myfood != null)
                    {
                        utils.LogActivity("Eating");
                        Styx.CommonBot.Rest.DrinkImmediate();
                        return true;
                    }
                    return true;
                }
                return false;
            }
        }

        public override bool NeedPullBuffs
        {
            get
            {
                return Buff();
            }
        }

        public override bool NeedCombatBuffs { get { return Buff(); } }

        public override bool NeedPreCombatBuffs { get { return Buff(); } }

        private bool BotUpdate()
        {
            if (BaseBot.Equals(BotManager.Current.Name))
                return false;
            if (utils.IsBotBaseInUse("LazyRaider") || utils.IsBotBaseInUse("Tyrael")
                || utils.IsBotBaseInUse("Raid Bot") || utils.IsBotBaseInUse("Enyo"))
            {
                SoloBotType = false;
                BaseBot = BotManager.Current.Name;
                Logging.Write("Base bot detected: " + BotManager.Current.Name);
                return true;
            }

            Logging.Write("Base bot detected: " + BotManager.Current.Name);
            SoloBotType = true;
            BaseBot = BotManager.Current.Name;
            return true;


        }

        private void SetTargetToAttack()
        {
            if (RestorationShamanSettings.Instance.TargetTypeSelected == RestorationShamanSettings.TargetType.AUTO)
            {
                if (ExtraUtilsSettings.Instance.provinGround_Targeting)
                    target = utils.getAnyTargetToAttack(40f);
                else
                    target = utils.getTargetToAttack(30f, tank, false, ExtraUtilsSettings.Instance.UseBossLogic);
                //if (target != null)
                    //target.Target();
            }
            else
                target = Me.CurrentTarget;
        }

        private bool CanCastFlameShock()
        {
            return utils.GetSpellCooldown(FLAME_SHOCK).TotalMilliseconds <= 2 * StyxWoW.WoWClient.Latency;
        }

        private bool DPS()
        {
            if (RestorationShamanSettings.Instance.UseFireTotems)
                if (UseFireTotem())
                    return true;
            if (!Me.IsFacing(target) && !Me.IsMoving && (RestorationShamanSettings.Instance.AutofaceTarget || SoloBotType))
                target.Face();
            if (RestorationShamanSettings.Instance.UseFlameShock && CanCastFlameShock() && (utils.MyAuraTimeLeft(FLAME_SHOCK, target) <= 9000) && Me.IsFacing(target)
                && target.Distance-target.CombatReach-1 <=25)
            {
                utils.LogActivity(FLAME_SHOCK, target.SafeName);
                return utils.Cast(FLAME_SHOCK, target);
            }
            if (RestorationShamanSettings.Instance.UseLavaBurst && !Me.IsCasting && !utils.IsGlobalCooldown() && Me.IsFacing(target) && utils.CanCast(LAVA_BURST) 
                && utils.MyAuraTimeLeft(FLAME_SHOCK, target) >= 2000 && (!Me.IsMoving || utils.isAuraActive(SPIRIT_WALK))
               )
            {
                utils.LogActivity(LAVA_BURST, target.SafeName);
                return utils.Cast(LAVA_BURST, target);
            }
            if (RestorationShamanSettings.Instance.UseChainLightning && !Me.IsCasting && !utils.IsGlobalCooldown() && Me.IsFacing(target)
                && (!Me.IsMoving || utils.isAuraActive(SPIRIT_WALK)) )
            {
                WoWUnit chainLightningCandidateTarget = utils.EnemyInRangeWithMobsAround(40f, 15f, 2, true, ExtraUtilsSettings.Instance.provinGround_Targeting);
                if (chainLightningCandidateTarget != null)
                {
                    utils.LogActivity(CHAIN_LIGHTNING, chainLightningCandidateTarget.SafeName);
                    return utils.Cast(CHAIN_LIGHTNING, chainLightningCandidateTarget);
                }
            }
            if (RestorationShamanSettings.Instance.UseLightningBolt && !Me.IsCasting && !utils.IsGlobalCooldown() && Me.IsFacing(target)
                && (!Me.IsMoving || utils.isAuraActive(SPIRIT_WALK))
               )
            {
                utils.LogActivity(LIGHTNING_BOLT, target.SafeName);
                return utils.Cast(LIGHTNING_BOLT, target);
            }
            

            return false;
        }

        private bool Self()
        {
            if (Me.HealthPercent <= RestorationShamanSettings.Instance.AS_HP && utils.CanCast(ASTRAL_SHIFT))
            {
                utils.LogActivity(ASTRAL_SHIFT);
                return utils.Cast(ASTRAL_SHIFT, Me);
            }

            if (RestorationShamanSettings.Instance.SelfHealingPriorityEnabled && Me.HealthPercent <= RestorationShamanSettings.Instance.SelfHealingPriorityHP)
            {    
                if ((!Me.IsMoving || utils.isAuraActive(SPIRIT_WALK)) && !Me.IsCasting && !utils.IsGlobalCooldown() && Me.HealthPercent < RestorationShamanSettings.Instance.HealingSurgePercent && utils.CanCast(HEALING_SURGE))
                {
                    utils.LogHealActivity(Me, HEALING_SURGE, Me.SafeName);
                    CurrentHealtarget = Me;
                    return utils.Cast(HEALING_SURGE, Me);
                }            
            }

            //buff me with elemental_Blast
            /*if (target != null && utils.CanCast(ELEMENTAL_BLAST) && target.Distance-target.CombatReach-1<=30f)
            {
                if (!Me.IsMoving && !Me.IsFacing(target))
                    Me.SetFacing(target);
                if(Me.IsFacing(target))
                {
                utils.LogActivity(ELEMENTAL_BLAST,target.SafeName);
                return utils.Cast(ELEMENTAL_BLAST, target);
                }
            }*/
            return false;
        }

        private bool AoE()
        {

            if (!RestorationShamanSettings.Instance.DisableAOE_HealingRotation)
            {
                
                //Spirit Link Totem
                if (!utils.isAuraActive(SPIRIT_LINK_TOTEM) && utils.AOEHealCount(Me, RestorationShamanSettings.Instance.SpiritLinkPercent, 10, RestorationShamanSettings.Instance.HealNPC) >= RestorationShamanSettings.Instance.SpiritLinkNumber
                    && utils.CanCast(SPIRIT_LINK_TOTEM))
                {
                    utils.LogActivity(SPIRIT_LINK_TOTEM);
                    return utils.Cast(SPIRIT_LINK_TOTEM);
                }

                //Healing Tide Totem 
                if (utils.CanCast(HEALING_TIDE_TOTEM) && !StyxWoW.Me.Totems.Any(t => t.WoWTotem == WoWTotem.HealingTide ))
                {                 
                    if (utils.AOEHealCount(Me, RestorationShamanSettings.Instance.HealingTideTotemPercent, 40, RestorationShamanSettings.Instance.HealNPC) >= RestorationShamanSettings.Instance.HealingTideTotemNumber)
                    {
                        utils.LogActivity(HEALING_TIDE_TOTEM);
                        return utils.Cast(HEALING_TIDE_TOTEM);
                    }                 
                }

                //Chain Heal
                ChainHeal();

                //Healing Stream Totem
                if (utils.CanCast(HEALING_STREAM_TOTEM) &&
                   !StyxWoW.Me.Totems.Any(t => t.WoWTotem == WoWTotem.HealingTide || t.WoWTotem == WoWTotem.HealingStream)
                    && !utils.isAuraActive(CLOUDBURST_TOTEM))
                {
                    switch (RestorationShamanSettings.Instance.WhenCastStreamTotem)
                    {
                        case RestorationShamanSettings.healingTotemCastType.ALWAYS:
                            {
                                utils.LogActivity(HEALING_STREAM_TOTEM);
                                return utils.Cast(HEALING_STREAM_TOTEM);
                            }
                        case RestorationShamanSettings.healingTotemCastType.AT_CONDITION:
                            {
                                if (utils.AOEHealCount(Me, RestorationShamanSettings.Instance.StreamTotemPercent, 30f, RestorationShamanSettings.Instance.HealNPC) >= RestorationShamanSettings.Instance.StreamTotemNumber)
                                {
                                    utils.LogActivity(HEALING_STREAM_TOTEM);
                                    return utils.Cast(HEALING_STREAM_TOTEM);
                                }
                                break;
                            }
                    }
                }

                //Cloudburst Totem
                if (utils.CanCast(CLOUDBURST_TOTEM) &&
                   !StyxWoW.Me.Totems.Any(t => t.WoWTotem == WoWTotem.HealingTide || t.WoWTotem == WoWTotem.HealingStream))
                {
                    utils.LogActivity(CLOUDBURST_TOTEM);
                    return utils.Cast(CLOUDBURST_TOTEM);
                }

                HealingRain();
                

            }
            return false;
        }

        private bool ProcWorks()
        {
            /*if (healTarget!=null && utils.isAuraActive(ECHO_OF_THE_ELEMENTS_BUFF) && !utils.isAuraActive(UNLEASH_LIFE) && utils.CanCast(UNLEASH_LIFE))
            {
                utils.LogActivity(UNLEASH_LIFE, healTarget.SafeName);
                utils.Cast(UNLEASH_LIFE, healTarget);
            }*/
            if (ChainHealT17()) return true;
            return false;
        }

        private bool Healing()
        {
            if (healTarget != null && !Me.IsCasting && !utils.IsGlobalCooldown())
            {
                //we are targetting an npc to full: if we are at this point then our healing settings cant full
                //the target so we spam Heal
                if (RestorationShamanSettings.Instance.HealNPC && RestorationShamanSettings.Instance.FullSelectedNPC
                    && !Me.IsCasting && !utils.IsGlobalCooldown()
                    && Me.CurrentTarget != null && Me.CurrentTarget.IsFriendly && !Me.CurrentTarget.Attackable && !Me.CurrentTarget.IsPlayer
                    && !Me.CurrentTarget.IsDead && Me.CurrentTarget.HealthPercent < 99
                    && Me.CurrentTarget.Distance - Me.CurrentTarget.CombatReach - 1 <= 40f && Me.CurrentTarget.InLineOfSpellSight)
                {
                    if (!utils.isMyAuraActive(RIPTIDE, Me.CurrentTarget) && utils.CanCast(RIPTIDE))
                    {
                        utils.LogHealActivity(Me.CurrentTarget, "FULL NPC CURRENT TARGET: RIPTIDE", Me.CurrentTarget.SafeName);
                        return utils.Cast(RIPTIDE, Me.CurrentTarget);
                    }
                    if (!utils.isAuraActive(UNLEASH_LIFE) && utils.CanCast(UNLEASH_LIFE))
                    {
                        utils.LogActivity(UNLEASH_LIFE, Me.CurrentTarget.SafeName);
                        utils.Cast(UNLEASH_LIFE, Me.CurrentTarget);
                    }
                    if (utils.CanCast(ANCESTRAL_SWIFTNESS) && utils.CanCast(HEALING_WAVE))
                    {
                        utils.LogActivity(ANCESTRAL_SWIFTNESS);
                        utils.Cast(ANCESTRAL_SWIFTNESS);
                        utils.LogHealActivity(Me.CurrentTarget, HEALING_WAVE, Me.CurrentTarget.SafeName);
                        return utils.Cast(HEALING_WAVE, Me.CurrentTarget);
                    }
                    if ((!Me.IsMoving || utils.isAuraActive(SPIRIT_WALK)) && !Me.IsCasting && !utils.IsGlobalCooldown() && utils.CanCast(HEALING_SURGE))
                    {
                        utils.LogHealActivity(Me.CurrentTarget, HEALING_SURGE, Me.CurrentTarget.SafeName);
                        CurrentHealtarget = Me.CurrentTarget;
                        return utils.Cast(HEALING_SURGE, Me.CurrentTarget);
                    }
                }

                double hp = healTarget.HealthPercent;
                if (RestorationShamanSettings.Instance.MantainTidalWaves && !utils.isAuraActive(TIDAL_WAVES) && utils.CanCast(RIPTIDE))
                {
                    WoWUnit candidateRiptide = utils.GetNeedMyAuraTarget(RIPTIDE, 40f, RestorationShamanSettings.Instance.HealNPC);
                    if (candidateRiptide == null)
                    {
                        candidateRiptide = healTarget;
                    }
                    utils.LogActivity("RIPTIDE to Mantain TIDAL WAVES on " + candidateRiptide.SafeName);
                    return utils.Cast(RIPTIDE, candidateRiptide);
                }
                if (Me.Combat && hp <= RestorationShamanSettings.Instance.HealingSurgePercent && Me.IsMoving && !utils.isAuraActive(SPIRIT_WALK) && RestorationShamanSettings.Instance.Autocast_Spirit_Walk)
                {
                    utils.LogActivity(SPIRIT_WALK);
                    return utils.Cast(SPIRIT_WALK);
                }           
                if (hp <= RestorationShamanSettings.Instance.HealingSurgePercent)
                {
                    if (!utils.isAuraActive(UNLEASH_LIFE) && utils.CanCast(UNLEASH_LIFE))
                    {
                        utils.LogActivity(UNLEASH_LIFE, healTarget.SafeName);
                        utils.Cast(UNLEASH_LIFE, healTarget);
                    }
                    if (utils.CanCast(ANCESTRAL_SWIFTNESS) && utils.CanCast(HEALING_WAVE))
                    {
                        utils.LogActivity(ANCESTRAL_SWIFTNESS);
                        utils.Cast(ANCESTRAL_SWIFTNESS);
                        utils.LogHealActivity(healTarget, HEALING_WAVE, healTarget.SafeName);
                        return utils.Cast(HEALING_WAVE, healTarget);
                    }
                    if ((!Me.IsMoving || utils.isAuraActive(SPIRIT_WALK)) && !Me.IsCasting && !utils.IsGlobalCooldown() && utils.CanCast(HEALING_SURGE))
                    {
                        utils.LogHealActivity(healTarget, HEALING_SURGE, healTarget.SafeName);
                        CurrentHealtarget = healTarget;
                        return utils.Cast(HEALING_SURGE, healTarget);
                    }
                }

                //we are targetting an npc to full: if we are at this point then our healing settings cant full
                //the target so we spam Heal
                if (RestorationShamanSettings.Instance.HealNPC && RestorationShamanSettings.Instance.FullSelectedNPC
                && Me.CurrentTarget != null && Me.CurrentTarget.IsFriendly && !Me.CurrentTarget.IsPlayer
                && !Me.CurrentTarget.IsDead && Me.CurrentTarget.HealthPercent < 100
                && Me.CurrentTarget.Distance - Me.CurrentTarget.CombatReach - 1 <= 40f && Me.CurrentTarget.InLineOfSpellSight)
                {
                    if (!utils.isMyAuraActive(RIPTIDE, Me.CurrentTarget) && utils.CanCast(RIPTIDE))
                    {
                        utils.LogHealActivity(Me.CurrentTarget, RIPTIDE, Me.CurrentTarget.SafeName);
                        return utils.Cast(RIPTIDE, Me.CurrentTarget);
                    }
                    if (Me.CurrentTarget.HealthPercent < 90 && utils.CanCast(HEALING_SURGE) && (!Me.IsMoving || utils.isAuraActive(SPIRIT_WALK)) && !Me.IsCasting && !utils.IsGlobalCooldown())
                    {
                        utils.LogHealActivity(Me.CurrentTarget, HEALING_SURGE, Me.CurrentTarget.SafeName);
                        CurrentHealtarget = Me.CurrentTarget;
                        return utils.Cast(HEALING_SURGE, Me.CurrentTarget);
                    }
                    if (utils.CanCast(HEALING_WAVE) && (!Me.IsMoving || utils.isAuraActive(SPIRIT_WALK)) && !Me.IsCasting && !utils.IsGlobalCooldown())
                    {
                        utils.LogHealActivity(Me.CurrentTarget, HEALING_WAVE, Me.CurrentTarget.SafeName);
                        CurrentHealtarget = Me.CurrentTarget;
                        return utils.Cast(HEALING_WAVE, Me.CurrentTarget);
                    }
                }

                if (hp <= RestorationShamanSettings.Instance.RiptidePercent && !utils.isMyAuraActive(RIPTIDE, healTarget) && utils.CanCast(RIPTIDE))
                {
                    utils.LogHealActivity(healTarget, RIPTIDE, healTarget.SafeName);
                    return utils.Cast(RIPTIDE, healTarget);
                }

                //buff me with elemental_Blast
                if (!utils.isAuraActive(ASCENDANCE) && hp >= RestorationShamanSettings.Instance.ElementalBlastHP && target != null && utils.CanCast(ELEMENTAL_BLAST) && target.Distance - target.CombatReach - 1 <= 30f)
                {
                    if (!Me.IsMoving && !Me.IsFacing(target))
                        Me.SetFacing(target);
                    if (Me.IsFacing(target))
                    {
                        utils.LogActivity(ELEMENTAL_BLAST, target.SafeName);
                        return utils.Cast(ELEMENTAL_BLAST, target);
                    }
                }

                if (RiptideSpam()) return true;

                

                if (hp <= RestorationShamanSettings.Instance.HealingWavePercent && utils.CanCast(HEALING_WAVE) && (!Me.IsMoving || utils.isAuraActive(SPIRIT_WALK)) && !Me.IsCasting && !utils.IsGlobalCooldown())
                {
                    if (utils.SpellCharges(UNLEASH_LIFE) ==2 &&  !utils.isAuraActive(UNLEASH_LIFE) && utils.CanCast(UNLEASH_LIFE))
                    {
                        utils.LogActivity(UNLEASH_LIFE, healTarget.SafeName);
                        utils.Cast(UNLEASH_LIFE, healTarget);
                    }
                    utils.LogHealActivity(healTarget, HEALING_WAVE, healTarget.SafeName);
                    CurrentHealtarget = healTarget;
                    return utils.Cast(HEALING_WAVE, healTarget);
                }

                
                
                
            }
            return false;
        }

        private bool Interrupt()
        {
            if (RestorationShamanSettings.Instance.AutoInterrupt)
            {
                WoWUnit InterruptTargetCandidate = Me.FocusedUnit;
                if (InterruptTargetCandidate == null || InterruptTargetCandidate.IsDead || !InterruptTargetCandidate.Attackable || !InterruptTargetCandidate.InLineOfSpellSight
                    || InterruptTargetCandidate.Distance - InterruptTargetCandidate.CombatReach - 1 > 25f)
                {
                    if (Me.CurrentTarget != null && Me.CurrentTarget.Attackable && Me.CurrentTarget.Distance - Me.CurrentTarget.CombatReach - 1 <= 25f && Me.CurrentTarget.InLineOfSpellSight)
                        InterruptTargetCandidate = Me.CurrentTarget;
                    else if (target != null && target.Attackable && target.Distance - target.CombatReach - 1 <= 25f && target.InLineOfSpellSight)
                        InterruptTargetCandidate = target;
                }
                if (InterruptTargetCandidate != null && (InterruptTargetCandidate.IsCasting || InterruptTargetCandidate.IsChanneling)
                    && InterruptTargetCandidate.CanInterruptCurrentSpellCast && utils.CanCast(WIND_SHEAR, InterruptTargetCandidate)
                    && Me.IsFacing(InterruptTargetCandidate)
                    && InterruptTargetCandidate.Distance - InterruptTargetCandidate.CombatReach - 1 <= 25f
                    && InterruptTargetCandidate.InLineOfSpellSight
                    && InterruptTargetCandidate.Attackable)
                {
                    RANDOM_TIME = rnd.Next(RestorationShamanSettings.Instance.Interrupt_MIN_Time, RestorationShamanSettings.Instance.Interrupt_MAX_Time);

                    if (InterruptTargetCandidate.CurrentCastStartTime.AddMilliseconds(RANDOM_TIME) <= DateTime.Now)
                    {
                        utils.LogActivity(WIND_SHEAR, InterruptTargetCandidate.SafeName);
                        return utils.Cast(WIND_SHEAR, InterruptTargetCandidate);
                    }
                }
            }
            return false;
        }

        private bool CC()
        {
            WoWUnit focused_unit = Me.FocusedUnit;
            if (RestorationShamanSettings.Instance.UseHex && focused_unit != null && focused_unit.Attackable && focused_unit.InLineOfSpellSight &&
                focused_unit.Distance <= 30 && !utils.isAuraActive(HEX, focused_unit) && utils.CanCast(HEX) && focused_unit.Guid != target.Guid
                && Me.IsFacing(focused_unit))
            {
                utils.LogActivity(HEX, focused_unit.SafeName);
                return utils.Cast(HEX, focused_unit);
            }
            return false;
        }

        private bool TankHealing()
        {
            if (tank != null && tank.IsAlive && tank.Distance < 40 && utils.IsHealableByMe(tank) && tank.InLineOfSpellSight && tank.IsValid && !tank.Possessed && tank.VehicleInfo == null) 
            {
                //earth shield
                if (tank.Guid != Me.Guid && (!utils.isAuraActive(EARTH_SHIELD, tank) || utils.GetAuraStack(tank,EARTH_SHIELD,false) <= 1) && utils.CanCast(EARTH_SHIELD))
                {
                    utils.LogActivity(EARTH_SHIELD, tank.SafeName);
                    return utils.Cast(EARTH_SHIELD, tank);
                }
                //riptide if configured always up
                if (RestorationShamanSettings.Instance.RiptideAlwaysUPOnTank && utils.MyAuraTimeLeft(RIPTIDE,tank) <= 1500 && utils.CanCast(RIPTIDE))
                {
                    if (utils.SpellCharges(UNLEASH_LIFE) == 2 && !utils.isAuraActive(UNLEASH_LIFE) && utils.CanCast(UNLEASH_LIFE)
                        && tank.HealthPercent <= RestorationShamanSettings.Instance.HealingWavePercent)
                    {
                        utils.LogActivity(UNLEASH_LIFE, tank.SafeName);
                        utils.Cast(UNLEASH_LIFE, tank);
                    }
                    utils.LogActivity(RIPTIDE, tank.SafeName);
                    return utils.Cast(RIPTIDE, tank);
                }
                if (tank.HealthPercent <= RestorationShamanSettings.Instance.HealingSurgePercent)
                {
                    if (!utils.isAuraActive(UNLEASH_LIFE) && utils.CanCast(UNLEASH_LIFE))
                    {
                        utils.LogActivity(UNLEASH_LIFE, tank.SafeName);
                        return utils.Cast(UNLEASH_LIFE, tank);
                    }
                    if (utils.CanCast(ANCESTRAL_SWIFTNESS) && utils.CanCast(HEALING_WAVE))
                    {
                        utils.LogActivity(ANCESTRAL_SWIFTNESS);
                        utils.Cast(ANCESTRAL_SWIFTNESS);
                        utils.LogHealActivity(tank, HEALING_WAVE, tank.SafeName);
                        return utils.Cast(HEALING_WAVE, tank);
                    }
                    if ((!Me.IsMoving || utils.isAuraActive(SPIRIT_WALK)) && !Me.IsCasting && !utils.IsGlobalCooldown() && utils.CanCast(HEALING_SURGE))
                    {
                        utils.LogHealActivity(tank, HEALING_SURGE, tank.SafeName);
                        CurrentHealtarget = tank;
                        return utils.Cast(HEALING_SURGE, tank);
                    }
                }
            }
            
            return false;
        }

        private bool OffTankHealing()
        {
            if (off_tank != null && off_tank.IsAlive && off_tank.Distance < 40 && utils.IsHealableByMe(tank) && tank.InLineOfSpellSight && tank.IsValid && !tank.Possessed && tank.VehicleInfo == null) 
            {
                //riptide if configured always up
                if (RestorationShamanSettings.Instance.RiptideAlwaysUPOnTank && utils.MyAuraTimeLeft(RIPTIDE, off_tank) <= 1500 && utils.CanCast(RIPTIDE))
                {
                    if (utils.SpellCharges(UNLEASH_LIFE) == 2 && !utils.isAuraActive(UNLEASH_LIFE) && utils.CanCast(UNLEASH_LIFE) 
                        && off_tank.HealthPercent <= RestorationShamanSettings.Instance.HealingWavePercent)
                    {
                        utils.LogActivity(UNLEASH_LIFE, off_tank.SafeName);
                        utils.Cast(UNLEASH_LIFE, off_tank);
                    }
                    utils.LogActivity(RIPTIDE, off_tank.SafeName);
                    return utils.Cast(RIPTIDE, off_tank);
                }
                if (off_tank.HealthPercent <= RestorationShamanSettings.Instance.HealingSurgePercent)
                {
                    if (!utils.isAuraActive(UNLEASH_LIFE) && utils.CanCast(UNLEASH_LIFE))
                    {
                        utils.LogActivity(UNLEASH_LIFE, off_tank.SafeName);
                        return utils.Cast(UNLEASH_LIFE, off_tank);
                    }
                    if (utils.CanCast(ANCESTRAL_SWIFTNESS) && utils.CanCast(HEALING_WAVE))
                    {
                        utils.LogActivity(ANCESTRAL_SWIFTNESS);
                        utils.Cast(ANCESTRAL_SWIFTNESS);
                        utils.LogHealActivity(off_tank, HEALING_WAVE, off_tank.SafeName);
                        return utils.Cast(HEALING_WAVE, off_tank);
                    }
                    if ((!Me.IsMoving || utils.isAuraActive(SPIRIT_WALK)) && !Me.IsCasting && !utils.IsGlobalCooldown() && utils.CanCast(HEALING_SURGE))
                    {
                        utils.LogHealActivity(off_tank, HEALING_SURGE, off_tank.SafeName);
                        CurrentHealtarget = off_tank;
                        return utils.Cast(HEALING_SURGE, off_tank);
                    }
                }
            }

            return false;
        }

        private bool UseCD()
        {
            //Empower
            if (talents.IsSelected(17)/*primalElementalist*/ && StyxWoW.Me.Totems.Any(t => t.WoWTotem == WoWTotem.FireElemental)
                && utils.CanCastPetAction(EMPOWER) && !utils.isAuraActive(EMPOWER))
            {
                utils.LogActivity(EMPOWER);
                utils.CastPetAction(EMPOWER);
            }

            //Reinforce
            if (talents.IsSelected(17)/*primalElementalist*/ && StyxWoW.Me.Totems.Any(t => t.WoWTotem == WoWTotem.EarthElemental)
                && utils.CanCastPetAction(REINFORCE) && !utils.isAuraActive(REINFORCE))
            {           
                utils.LogActivity(REINFORCE);
                utils.CastPetAction(REINFORCE);             
            }
            if (Me.Combat)
            {
                if (utils.CanCast(ELEMENTAL_MASTERY) && 
                    (RestorationShamanSettings.Instance.ElementalMasteryCD == RestorationShamanSettings.CDUseType.COOLDOWN)
                    || (extra.IsTargetBoss() && RestorationShamanSettings.Instance.ElementalMasteryCD == RestorationShamanSettings.CDUseType.BOSS))
                {
                    if ((utils.GetMemberCountBelowThreshold(RestorationShamanSettings.Instance.ElementalMasteryHP,40f,RestorationShamanSettings.Instance.HealNPC) >= RestorationShamanSettings.Instance.ElementalMasteryNumber))
                    {
                        utils.LogActivity(ELEMENTAL_MASTERY);
                        return utils.Cast(ELEMENTAL_MASTERY);
                    }
                }
                
                if (!utils.isAuraActive(ASCENDANCE) && utils.CanCast(ASCENDANCE) &&
                    (RestorationShamanSettings.Instance.AscendanceCD == RestorationShamanSettings.CDUseType.COOLDOWN)
                    || (extra.IsTargetBoss() && RestorationShamanSettings.Instance.AscendanceCD == RestorationShamanSettings.CDUseType.BOSS))
                {
                    if ((utils.GetMemberCountBelowThreshold(RestorationShamanSettings.Instance.AscendanceHP, 40f, RestorationShamanSettings.Instance.HealNPC) >= RestorationShamanSettings.Instance.AscendanceNumber))
                    {
                        utils.LogActivity(ASCENDANCE);
                        return utils.Cast(ASCENDANCE);
                    }
                }

                if (talents.IsSelected(17) && (RestorationShamanSettings.Instance.ElementalCD == RestorationShamanSettings.CDUseType.COOLDOWN 
                    || (extra.IsTargetBoss() && RestorationShamanSettings.Instance.ElementalCD == RestorationShamanSettings.CDUseType.BOSS )) 
                    && (utils.GetMemberCountBelowThreshold(RestorationShamanSettings.Instance.ElementalHP,40f,RestorationShamanSettings.Instance.HealNPC) >= RestorationShamanSettings.Instance.ElementalNumber))
                    
                {
                    
                    if (utils.CanCast(FIRE_ELEMENTAL_TOTEM))
                    {
                    
                        utils.LogActivity(FIRE_ELEMENTAL_TOTEM);
                        return utils.Cast(FIRE_ELEMENTAL_TOTEM);

                    }
                    if (utils.CanCast(EARTH_ELEMENTAL_TOTEM))
                    {
                        utils.LogActivity(EARTH_ELEMENTAL_TOTEM);
                        return utils.Cast(EARTH_ELEMENTAL_TOTEM);
                    }

                }
                if (!talents.IsSelected(17) && (RestorationShamanSettings.Instance.ElementalCD == RestorationShamanSettings.CDUseType.COOLDOWN
                    || (extra.IsTargetBoss() && RestorationShamanSettings.Instance.ElementalCD == RestorationShamanSettings.CDUseType.BOSS)))
                {
                    if (utils.CanCast(FIRE_ELEMENTAL_TOTEM))
                    {
                    
                        utils.LogActivity(FIRE_ELEMENTAL_TOTEM);
                        return utils.Cast(FIRE_ELEMENTAL_TOTEM);

                    }
                    if (utils.CanCast(EARTH_ELEMENTAL_TOTEM))
                    {
                        utils.LogActivity(EARTH_ELEMENTAL_TOTEM);
                        return utils.Cast(EARTH_ELEMENTAL_TOTEM);
                    }
                }
            }
            return false;
        }

        private bool Cleansing()
        {
            if (RestorationShamanSettings.Instance.UseDispell)
            {
                WoWUnit player = null;
                if (utils.NeedsDispelShammy(Me, ExtraUtilsSettings.Instance.UseBossLogic))
                    player = Me;
                else if (tank != null && tank.IsAlive && tank.InLineOfSpellSight && tank.Distance - tank.CombatReach - 1 <= 40f && utils.NeedsDispelShammy(tank, ExtraUtilsSettings.Instance.UseBossLogic))
                    player = tank;
                else if (off_tank != null && off_tank.IsAlive && off_tank.InLineOfSpellSight && off_tank.Distance - off_tank.CombatReach - 1 <= 40f && utils.NeedsDispelShammy(off_tank, ExtraUtilsSettings.Instance.UseBossLogic))
                    player = off_tank;
                else
                    player = utils.GetDispellTargetShammy(40f,RestorationShamanSettings.Instance.HealNPC,ExtraUtilsSettings.Instance.UseBossLogic);
                if (player != null)
                {
                    if (utils.CanCast(PURIFY_SPIRIT))
                    {
                        utils.LogActivity(PURIFY_SPIRIT, player.SafeName);
                        return utils.Cast(PURIFY_SPIRIT, player);
                    }
                }
            }
            return false;
        }

        private bool Resurrect()
        {
            foreach (WoWPlayer player in utils.GetResurrectTargets(40f))
            {
                if (Blacklist.Contains(player.Guid, BlacklistFlags.All)) continue;
                else
                {
                    if (player.Distance > 40 || !player.InLineOfSpellSight) return false;
                    else if (utils.CanCast(ANCESTRAL_SPIRIT, player) && RestorationShamanSettings.Instance.UseResurrection && !Me.IsMoving)
                    {
                        utils.LogActivity(ANCESTRAL_SPIRIT, player.SafeName);
                        Blacklist.Add(player,BlacklistFlags.All, new TimeSpan(0, 0, 60));
                        return utils.Cast(ANCESTRAL_SPIRIT, player);
                    }

                    return false;
                }
            }

            return false;
        }

        private bool Buff()
        {
            if (utils.Mounted() || IsCRPaused/*ExtraUtilsSettings.Instance.PauseRotation || */)
                return false;
            

            //shield
            if (!utils.isAuraActive(WATER_SHIELD, Me) && utils.CanCast(WATER_SHIELD))
            {
                utils.LogActivity(WATER_SHIELD);
                return utils.Cast(WATER_SHIELD);
            }
            return false;
        }

        private bool SoS()
        {
            if (RestorationShamanSettings.Instance.UseSoS && healTarget != null && healTarget.HealthPercent <= RestorationShamanSettings.Instance.SoSHP)
            {
                if (!utils.isAuraActive(UNLEASH_LIFE) && utils.CanCast(UNLEASH_LIFE))
                {
                    utils.LogActivity("SoS: " + UNLEASH_LIFE, healTarget.SafeName);
                    utils.Cast(UNLEASH_LIFE, healTarget);
                }
                if (utils.CanCast(ANCESTRAL_SWIFTNESS) && utils.CanCast(HEALING_WAVE))
                {
                    utils.LogActivity("SoS: " + ANCESTRAL_SWIFTNESS);
                    utils.Cast(ANCESTRAL_SWIFTNESS);
                    utils.LogHealActivity(healTarget, HEALING_WAVE, healTarget.SafeName);
                    return utils.Cast(HEALING_WAVE, healTarget);
                }
                if (!utils.isAuraActive(TIDAL_WAVES) && utils.CanCast(RIPTIDE) && !utils.isMyAuraActive(RIPTIDE, healTarget))
                {
                    utils.LogActivity("SoS: RIPTIDE for TIDAL WAVES" + healTarget.SafeName);
                    return utils.Cast(RIPTIDE, healTarget);
                }
                if ((!Me.IsMoving || utils.isAuraActive(SPIRIT_WALK)) && !Me.IsCasting && !utils.IsGlobalCooldown() && utils.CanCast(HEALING_SURGE))
                {
                    utils.LogHealActivity(healTarget, "SoS: " + HEALING_SURGE, healTarget.SafeName);
                    CurrentHealtarget = healTarget;
                    return utils.Cast(HEALING_SURGE, healTarget);
                }
            }            
            return false;
        }

        public bool CombatRotation()
        {
            SetTargetToAttack();
            if (RestorationShamanSettings.Instance.TrySaveMana) StopCastingCheck();
            if (HotkeyHandle()) return true;
            if (Cleansing()) return true;
            extra.UseHealPotion_Healthstone();
            if (extra.UseRacials()) return true;
            if (extra.UseTrinket1()) return true;
            if (extra.UseTrinket2()) return true;
            if (extra.UseManaItem()) return true;
            if (Buff()) return true;

            //relocate fire totem
            if (!Me.IsMoving && talents.IsSelected(9) && utils.CanCast(TOTEMIC_PROJECTION))
            {
                if (target.Entry != 77692 /*Kromog*/ && shammyCommon.NeedRelocateOrRecastFireTotemToReachUnit(target))
                {
                    utils.LogActivity(TOTEMIC_PROJECTION);
                    utils.Cast(TOTEMIC_PROJECTION);
                    return SpellManager.ClickRemoteLocation(target.Location);
                }
            }

            if (RestorationShamanSettings.Instance.movementEnabled && (!target.InLineOfSpellSight || target.Distance - target.CombatReach - 1 < RestorationShamanSettings.Instance.PullDistance))
            {
                movement.KingHealMove(target, RestorationShamanSettings.Instance.PullDistance);
            }

            if ((SoloBotType || RestorationShamanSettings.Instance.movementEnabled) && Me.IsMoving && target.InLineOfSpellSight && target.Distance - target.CombatReach - 1 <= RestorationShamanSettings.Instance.PullDistance)
            {
                Navigator.PlayerMover.MoveStop();
            }


            if (SoS()) return true;
            if (ProcWorks()) return true;
            if (Self()) return true;
            if (UseCD()) return true;
            if (AoE()) return true;
            if (TankHealing()) return true;
            if (OffTankHealing()) return true;
            if (Interrupt()) return true;
            if (CC()) return true;
            if (Healing()) return true;
            if (UseAirTotem()) return true;
            if (UseEarthTotem()) return true;
            if (target != null && target.Distance-target.CombatReach-1 <=30)
                DPS();
            if (RestorationShamanSettings.Instance.AutoGhostWulf && !utils.isAuraActive(GHOST_WOLF) && Me.IsMoving && !Me.Mounted && !Me.IsFalling && !Me.IsDead && !Me.IsGhost
                    && Me.MovementInfo.TimeMoved >= RestorationShamanSettings.Instance.MoveTimeForAutoGhostWulf && !IsCRPaused && !Me.IsCasting)
            {
                utils.LogActivity("moving....autoGhostWolf");
                return utils.Cast(GHOST_WOLF);
            }
            return false;

        }

        public void StopCastingCheck()
        {
            //Stop Casting Healing Spells
            if (Me.IsCasting &&
                (Me.CastingSpell.Name.Equals(HEALING_WAVE) || Me.CastingSpell.Name.Equals(HEALING_SURGE)))
            {
                if (CurrentHealtarget != null && (!CurrentHealtarget.IsValid || !CurrentHealtarget.IsAlive))
                {
                    CurrentHealtarget = null;
                    SpellManager.StopCasting();
                    Logging.Write(DateTime.Now.ToString("ss:fff ") + "Stop Casting: Unit is Dead");
                }                
                else if (CurrentHealtarget != null && CurrentHealtarget.IsAlive &&
                    (CurrentHealtarget.HealthPercent > RestorationShamanSettings.Instance.HealingWavePercent+5 || CurrentHealtarget.HealthPercent >= 99))
                {
                    CurrentHealtarget = null;
                    SpellManager.StopCasting();
                    Logging.Write(DateTime.Now.ToString("ss:fff ") + "Stop Casting: Unit Full HP or upper limit lower heal spell(HealingWavePercent+5)");
                }
              
            }
        }

        public override bool Combat
        {
            get
            {
                if ((Me.Mounted && !RestorationShamanSettings.Instance.AutoDismountOnCombat) || !StyxWoW.IsInGame || !StyxWoW.IsInWorld || Me.Silenced
                    /*|| (!ExtraUtilsSettings.Instance.FastRotation && (utils.IsGlobalCooldown() || Me.IsCasting || utils.MeIsChanneling))*/
                    || utils.IsGlobalCooldown() || Me.IsCasting || utils.MeIsChanneling
                || utils.IsEatingOrDrinking() || IsCRPaused)
                    return false;
                healTarget = utils.GetHealTarget(40f, RestorationShamanSettings.Instance.HealNPC);
                //UPDATE TANK
                //tank = utils.GetTank();
                tank = utils.SimpleGetTank(40f);
                if (tank == null || !tank.IsValid || !tank.IsAlive) tank = Me;

                if (tank != null && (lastTank == null || lastTank.Guid != tank.Guid))
                {
                    lastTank = tank;
                    utils.LogActivity(TANK_CHANGE, tank.SafeName);
                }
                off_tank = utils.SimpleGetOffTank(40f, tank);
                if (off_tank != null && (lastOffTank == null || lastOffTank.Guid != off_tank.Guid))
                {
                    lastOffTank = off_tank;
                    utils.LogActivity(OFF_TANK_CHANGE, off_tank.SafeName);
                }
                return CombatRotation();
            }
        }

        #region COMMON_TOTEM
        //********************** TOTEM *************************************//

        #region AIR_TOTEM
        //******************************** AIR AIR AIR AIR AIR ******************************************
        private bool CapacitorTotem()
        {
            if (Me.Combat && utils.CanCast(CAPACITOR_TOTEM) && !utils.IsGlobalCooldown() && !Me.IsCasting
                && utils.AllAttaccableEnemyMobsInRange(8f).Count() >= 1
                && !StyxWoW.Me.Totems.Any(t => t.WoWTotem == WoWTotem.Grounding || t.WoWTotem == WoWTotem.Capacitor || t.WoWTotem == WoWTotem.Windwalk))
            {
                utils.LogActivity(CAPACITOR_TOTEM);
                return utils.Cast(CAPACITOR_TOTEM);
            }
            return false;
        }

        private bool GroundingTotem()
        {
            if (Me.Combat && utils.CanCast(GROUNDING_TOTEM) && !utils.IsGlobalCooldown() && !Me.IsCasting
                && !StyxWoW.Me.Totems.Any(t => t.WoWTotem == WoWTotem.Grounding || t.WoWTotem == WoWTotem.Capacitor || t.WoWTotem == WoWTotem.Windwalk))
            {
                utils.LogActivity(GROUNDING_TOTEM);
                return utils.Cast(GROUNDING_TOTEM);
            }
            return false;
        }

        private bool WindwalkTotem()
        {
            if (Me.Combat && utils.CanCast(GROUNDING_TOTEM) && !utils.IsGlobalCooldown() && !Me.IsCasting
                && !StyxWoW.Me.Totems.Any(t => t.WoWTotem == WoWTotem.Grounding || t.WoWTotem == WoWTotem.Capacitor || t.WoWTotem == WoWTotem.Windwalk))
            {
                WoWUnit crowdControlledUnit = utils.GetCrowdControlledFriendlyUnit(40f);
                if (crowdControlledUnit != null)
                {
                    utils.LogActivity(WINDWALK_TOTEM);
                    return utils.Cast(WINDWALK_TOTEM);
                }
            }
            return false;
        }

        //*************************************************************************************//
        #endregion

        #region EARTH
        //******************************** EARTH EARTH EARTH EARTH EARTH ******************************************
        private bool EarthBindTotem()
        {
            if (Me.Combat && utils.CanCast(EARTHBIND_TOTEM) && !utils.IsGlobalCooldown() && !Me.IsCasting
                && !StyxWoW.Me.Totems.Any(t => t.WoWTotem == WoWTotem.Earthbind || t.WoWTotem == WoWTotem.EarthElemental || t.WoWTotem == WoWTotem.Tremor || t.WoWTotem == WoWTotem.Earthgrab)
                && utils.AllAttaccableEnemyMobsInRange(10f).Count() >= 1)
            {
                utils.LogActivity(EARTHBIND_TOTEM);
                return utils.Cast(EARTHBIND_TOTEM);
            }
            return false;
        }

        private bool EarthGrabTotem()
        {
            if (Me.Combat && utils.CanCast(EARTHGRAB_TOTEM) && !utils.IsGlobalCooldown() && !Me.IsCasting
                && !StyxWoW.Me.Totems.Any(t => t.WoWTotem == WoWTotem.Earthbind || t.WoWTotem == WoWTotem.EarthElemental || t.WoWTotem == WoWTotem.Tremor || t.WoWTotem == WoWTotem.Earthgrab)
                && utils.AllAttaccableEnemyMobsInRange(10f).Count() >= 1)
            {
                utils.LogActivity(EARTHGRAB_TOTEM);
                return utils.Cast(EARTHGRAB_TOTEM);
            }
            return false;
        }

        private bool TremorTotem()
        {
            if (Me.Combat && utils.CanCast(TREMOR_TOTEM) && !utils.IsGlobalCooldown() && !Me.IsCasting
                && !StyxWoW.Me.Totems.Any(t => t.WoWTotem == WoWTotem.Earthbind || t.WoWTotem == WoWTotem.EarthElemental || t.WoWTotem == WoWTotem.Tremor || t.WoWTotem == WoWTotem.Earthgrab)
                && utils.AllAttaccableEnemyMobsInRange(20f).Count() >= 1)
            {
                WoWUnit crowdControlledUnit = utils.GetCrowdControlledFriendlyUnit(40f);
                if (crowdControlledUnit != null)
                {
                    utils.LogActivity(TREMOR_TOTEM);
                    return utils.Cast(TREMOR_TOTEM);
                }
            }
            return false;
        }

        //*************************************************************************************************************
        #endregion
        //********************** TOTEM END *************************************//
        #endregion

        private bool UseFireTotem()
        {
            if (Me.Combat && utils.CanCast(SEARING_TOTEM) && !utils.IsGlobalCooldown() && !Me.IsCasting
                && !StyxWoW.Me.Totems.Any(t => t.WoWTotem == WoWTotem.FireElemental || t.WoWTotem == WoWTotem.Searing))
            {
                utils.LogActivity(SEARING_TOTEM);
                return utils.Cast(SEARING_TOTEM);
            }
            return false;
        }

        private bool UseAirTotem()
        {
            if (RestorationShamanSettings.Instance.UseWindWalkTotem && WindwalkTotem()) return true;
            if (RestorationShamanSettings.Instance.UseCapacitorTotem && CapacitorTotem()) return true;
            if (RestorationShamanSettings.Instance.UseGroundingTotem && GroundingTotem()) return true;
            return false;
        }

        private bool UseEarthTotem()
        {
            if (RestorationShamanSettings.Instance.UseTremorTotem && TremorTotem()) return true;
            if (RestorationShamanSettings.Instance.UseEarthGrabTotem && EarthGrabTotem()) return true;
            if (RestorationShamanSettings.Instance.UseEarthBindTotem && EarthBindTotem()) return true;
            return false;
        }
        
    }
}
